/**
 * Copyright (C) 2009 Marcel Urbanek
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.urbiworx.sugar;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

import com.google.inject.Key;
import com.google.inject.name.Names;

public class ClientScopePhaseListener implements PhaseListener{

	public static String CLIENTSCOPE="de.urbiworx.sugar.client";

	public void afterPhase(PhaseEvent event) {
		if (event.getPhaseId()==PhaseId.RENDER_RESPONSE)
		{
			event.getFacesContext().getExternalContext().getRequestMap().remove(CLIENTSCOPE);
		}
		else if (event.getPhaseId()==PhaseId.RESTORE_VIEW)
		{
			Map <String,String> requestParameterMap=event.getFacesContext().getExternalContext().getRequestParameterMap();
			{
				for (Map.Entry<String,String> entry:requestParameterMap.entrySet())
				{
					if (entry.getKey().startsWith("client_"))
					{						
						String name=entry.getKey().substring(7,entry.getKey().length());
						ObjectInputStream in;
						Object object=null;
						try {
							in = new ObjectInputStream(new ByteArrayInputStream(Base64.decode(entry.getValue())));
							object=in.readObject();	
						} catch (IOException e1) {
							throw new SugarException("Deserializationexception while trying to deserialize:"+name+" "+e1.getMessage());
						} catch (ClassNotFoundException e2) {
							throw new SugarException("Deserializationexception while trying to deserialize:"+name+" "+e2.getMessage());
						}
						SugarConfigurationEntry configurationEntry=SugarConfigurationHolder.getInstance().getConfiguration().get(name);
						String type=configurationEntry.getType();
						Key key=null;
						try {
							key = Key.get(getClass().getClassLoader().loadClass(type), Names.named(name));
						} catch (ClassNotFoundException e) {
							throw new SugarException("Class: "+type+" not found! Line:"+configurationEntry.getLine()+" file:"+configurationEntry.getFilename());
						}
						
						SugarScopeHelper.setObjectForKey(object, key);
					}
				}
			}			
			removeClientOutput(event.getFacesContext().getViewRoot());
		}

	}


	public void beforePhase(PhaseEvent event) {
		if (event.getPhaseId()==PhaseId.RENDER_RESPONSE)
		{
			event.getFacesContext().getExternalContext().getRequestMap().put(CLIENTSCOPE, new Boolean(true));
		}
	}

	public static boolean isRenderClientScope()
	{
		if (FacesContext.getCurrentInstance()==null)
		{
			return false;
		}
		return FacesContext.getCurrentInstance().getExternalContext().getRequestMap().containsKey(CLIENTSCOPE);
	}
	

	public PhaseId getPhaseId() {
		return PhaseId.ANY_PHASE;
	}

	
	private boolean removeClientOutput(UIComponent component)
	{
		boolean delete=false;
		if (component instanceof ClientStateOutput)
		{
			component.getParent().getChildren().remove(component);		
			delete=true;
		}
		if (component==null)
		{
			return false;
		}
		for (int i=0;i<component.getChildren().size();i++)
		{
			if (removeClientOutput(component.getChildren().get(i)))
			{
				i--;
			}
		}
		return delete;
	}

}
